feat(consensus): implement ZIP 218 behind a build feature - #851
Open
evan-forbes wants to merge 17 commits into
Open
feat(consensus): implement ZIP 218 behind a build feature#851evan-forbes wants to merge 17 commits into
evan-forbes wants to merge 17 commits into
Conversation
This was referenced Sep 1, 2026
evan-forbes
force-pushed
the
feat/zip218-blocktime-reduction
branch
from
September 5, 2026 05:22
c418772 to
25eb882
Compare
evan-forbes
marked this pull request as ready for review
September 5, 2026 05:24
czarcas7ic
reviewed
Sep 6, 2026
evan-forbes
force-pushed
the
feat/zip218-blocktime-reduction
branch
from
September 7, 2026 08:13
e76fe49 to
d2a03db
Compare
Implements ZIP 218 "25-second Block Target Spacing" (zcash/zips#1215), gated on the new `zip218` cargo feature so a default build keeps today's consensus. Even in a `zip218` build the rules stay dormant until NU7 has an activation height on the configured network, which no production network sets yet. Block target spacing and issuance: - `PostNU7PoWTargetSpacing` = 25 seconds, an NU7 era in `target_spacings`, and a `NU7PoWTargetSpacingRatio` of 3. - `halving` folds over the per-era spacings instead of branching on Blossom, and `block_subsidy` scales by `era_spacing / pre_blossom_spacing`. Both are the spec's segmented sum with the common denominator factored out, so a future spacing change is one tuple, not another branch. Issuance per unit of wall-clock time is unchanged. Difficulty: - `PostNU7PoWAveragingWindow` = 102, and `PoWAveragingWindow` becomes a height-dependent function that `AdjustedDifficulty` consults for the mean target and the median timespan. - `POW_ADJUSTMENT_BLOCK_SPAN` now covers the widest window the build can use, so a `zip218` build carries 113 predecessors of difficulty context from genesis and ignores the entries past the window in force at the candidate height. The span stays 28 in a default build. Shielded action limits: - Per-block limits of 330 Orchard actions, 300 Sapling spends + outputs, and 25 Sprout JoinSplits, plus a global shielded budget of 330 over `orchard + sapling_ios + 2 * joinsplits`. - `shielded_action_limits_are_valid` runs over any iterator of transactions: the block verifier passes the whole block, and the transaction verifier passes one transaction, so the mempool rejects a transaction whose own counts can never be mined. - `getblocktemplate` tracks the same limits through a `BlockTemplateLimits` struct, which replaces the three loose counters and the `TryUpdateBlockLimits` trait, so template selection cannot build a block the verifier would reject. The non-consensus constants ZIP 218 recommends scaling (the expiry delta, `MAX_REORG_LENGTH`, and the block download and retention windows) are left for a follow-up.
`linked_validation_context` hardcoded 27 predecessors, duplicating `POW_PREDECESSOR_CONTEXT_SPAN` rather than reading it. The recovery audit requires exactly `min(finalized_height, POW_PREDECESSOR_CONTEXT_SPAN)` context rows, so the two disagree as soon as the span changes, and full state initialization fails its own audit. Read the constant instead, and derive the boundary test's expectations from it. Also generalize the tests that hardcoded the 28-block difficulty adjustment span or the 17-block averaging window, and bump zakura-consensus to 8.0.0 for the new `TransactionError` variants.
The v1.4.0-rc0 release published the current crate versions without the zip218 features. Publish the stable forms of the affected crates and update each workspace requirement.
evan-forbes
force-pushed
the
feat/zip218-blocktime-reduction
branch
from
September 7, 2026 16:11
d40db49 to
123c7cf
Compare
…-reduction # Conflicts: # Cargo.lock # crates/zakura-consensus/Cargo.toml # crates/zakura-header-chain/Cargo.toml # crates/zakura-network/Cargo.toml # crates/zakura-node-services/Cargo.toml # crates/zakura-rpc/Cargo.toml # crates/zakura-script/Cargo.toml # crates/zakura-state/Cargo.toml # crates/zakura-utils/Cargo.toml # crates/zakurad/Cargo.toml
* feat(consensus): implement ZIP 2003 with a configurable deprecation height Implements ZIP 2003 "Disallow version 4 transactions". Zakura already rejected V4 transactions at NU7, but the height was welded to the NU7 activation height. The NU7 scope polls offer three deprecation dates, so `V4Deprecation` names the choice instead: - `AtNu7`, the ZIP 2003 default and today's behaviour, resolving to the NU7 activation height. A network that does not activate NU7 keeps accepting V4 transactions. - `AtHeight(height)`, for a network that activates NU7 and deprecates V4 transactions later. - `Never`, for a network that keeps accepting V4 transactions. `verify_v4_transaction_network_upgrade` now rejects on the resolved height rather than on the NU7 arm of its network upgrade match, so Mainnet and the default Testnet keep the rule they have today. Testnet configures the choice through `testnet_parameters.v4_deprecation`, which accepts `"nu7"`, `"never"`, or a block height. * docs(changelog): add the ZIP 2003 fragment * fix(consensus): require an exact NU7 v4 boundary * refactor(consensus): fix v4 deprecation at NU7 * refactor(consensus): gate v4 deprecation on experimental NU7
…-reduction Main's #958 added its own nu7-experimental feature. This merge keeps the branch's feature lists, which forward to more crates, and removes the duplicate key from zakurad. The CI job keeps the branch's tests and adds main's cargo check of the zakura package. # Conflicts: # .github/workflows/tests-unit.yml # crates/zakura-consensus/Cargo.toml # crates/zakurad/tests/common/configs/v1.4.0.toml
v1.4.0 published the current crate versions without the nu7-experimental features, so the publish graph could not resolve them. Patch-bump zakura-chain, zakura-header-chain and zakura-state, which gain the feature. Major-bump zakura-consensus, which adds variants to the exhaustive TransactionError enum. Point each dependent that enables the feature at the new versions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The current NU7 poll asks whether Zcash should adopt ZIP 218. ZIP 218 reduces the block target spacing from 75 seconds to 25 seconds. It also adds shielded action limits.
NU7 remains a candidate network upgrade. Its rules can change before deployment.
Solution
The off-by-default
nu7-experimentalCargo feature implements the current candidate NU7 rules. This branch adds the ZIP 218 rules to that feature. Every rule also requires an exact NU7 activation on the selected network. Mainnet and the default Testnet therefore retain current consensus until a deployment PR sets NU7.The implementation:
The implementation derives halving heights from the complete spacing schedule. It also represents pre-anchor funding-stream periods as signed integers. This keeps configured Testnets valid when they activate NU7 before the first halving.
The state migration backfills the wider difficulty context before it runs the startup consistency check. Existing databases therefore retain the required 112 predecessor headers when a node upgrades to an experimental NU7 build.
Zakura already meets or exceeds the ZIP's related node-policy recommendations. It permits reorgs up to 1,000 blocks and retains at least 10,000 blocks. Its native block sync bounds work by bytes and peer capacity. Zakura does not create ordinary wallet transactions, so it has no default wallet expiry delta to change.
Testing
Tests cover both sides of the NU7 activation boundary. They cover the exact subsidy, halving inversion, funding-stream period arithmetic, the 102-block averaging window, every per-pool limit, the global limit, mempool admission, block validation, block-template selection, shielded coinbase capacity, and upgrades from existing databases.
The audit passed:
zakura-chaintests withnu7-experimental;zakura-header-chaintests;nu7-experimental;actionlint .github/workflows/tests-unit.yml;The branch uses the current
1.1.0Zakura consensus-library releases frommain.Changelog
Added
docs/changelog/unreleased/851.md.Specifications & References
Follow-up Work
A deployment PR will replace the experimental feature with finalized NU7 rules and set the activation parameters.